<?php
namespace llkphp\workerman\command;

use think\Container;
use think\facade\Config;
use think\console\Command;
use think\console\Input;
use think\console\input\Argument;
use think\console\input\Option;
use think\console\Output;

use Workerman\Worker;
use Workerman\Connection\TcpConnection;

class Workerman extends Command
{
    public function configure()
    {
        $this->setName('workerman')
            ->addArgument('action', Argument::OPTIONAL, 'start|stop|restart|reload|status', 'start')
            ->addOption('daemon', 'd', Option::VALUE_NONE, 'daemon method run --daemon -d')
            ->addOption('server', 's', Option::VALUE_OPTIONAL, '要运行的服务名称')
            ->setDescription('Workerman Service');
    }

    public function execute(Input $input, Output $output)
    {
        $action = $input->getArgument('action');
        $daemon = $input->getOption('daemon');
        $server = $input->getOption('server');


        if ($this->checkEnv() === false) {
            return;
        }

        $this->init();
        
    }

    /**
     * 初始化项目
     */
    public function init()
    {
        $process = Config::get('workerman.process');
        
        foreach($process as $name => $config) {
            // 运行在主进程
            $worker = new Worker($config['listen']);

            $worker->onWorkerStart = function($worker) use ($config) {
                $classInstance = Container::getInstance()->make($config['handler']);

                $this->workermanCallback($worker, $classInstance);
            };
        }
        

        Worker::runAll();
    }

    public function workermanCallback(Worker $worker, $classInstance)
    {
        $eventMap = [
			'onConnect',
			'onMessage',
			'onClose',
			'onError',
			'onBufferFull',
			'onBufferDrain',
			'onWorkerStop',
			'onWebSocketConnect',
			'onWorkerReload'
		];

        foreach ($eventMap as $event) {
			if (method_exists($classInstance, $event)) {
				$worker->$event = function() use ($classInstance, $event) {
                    call_user_func_array([$classInstance, $event], func_get_args());
                };
			}
		}

        if (method_exists($classInstance, 'onWorkerStart')) {
			call_user_func([$classInstance, 'onWorkerStart'], $worker);
		}
    }

    /**
     * 检查环境
     */
    public function checkEnv()
    {
        // 需要启用的函数
        $enableFunctions = [
            'stream_socket_server',
            'stream_socket_client',
            'pcntl_signal_dispatch',
            'pcntl_signal',
            'pcntl_alarm',
            'pcntl_fork',
            'pcntl_wait',
            'posix_getuid',
            'posix_getpwuid',
            'posix_kill',
            'posix_setsid',
            'posix_getpid',
            'posix_getpwnam',
            'posix_getgrnam',
            'posix_getgid',
            'posix_setgid',
            'posix_initgroups',
            'posix_setuid',
            'posix_isatty',
        ];

        // 当前禁用的函数
        $disableFunctions = explode(',', ini_get('disable_functions'));
        foreach ($enableFunctions as $item) {
            if (in_array($item, $disableFunctions, true)) {
                $this->output->writeln('<error>function [' . $item . '] not enabled, workerman failed to successfully start.</error>');
                return false;
            }
        }

        return true;
    }

    public function array_kshift(&$arr)
    {
        list($k) = array_keys($arr);
        $r  = array($k=>$arr[$k]);
        unset($arr[$k]);
        return $r;
    }
}